package ch.fusun.baron.core.initialization;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;

import ch.fusun.baron.core.injection.ReInjector;

/**
 * Gets all the initializers from the configuration
 */
@SuppressWarnings("rawtypes")
public class GameInitializationUtilImpl implements GameInitializationUtil {

	private static final String DEPENDENCY = "dependency"; //$NON-NLS-1$
	private List<GameInitializer> initializers = new LinkedList<GameInitializer>();

	private final Map<GameInitializer, List> initializerDependencies = new HashMap<GameInitializer, List>();
	private static final String INITIALIZER_ID = "ch.fusun.baron.core.gameinitializer"; //$NON-NLS-1$
	private static final String INITIALIZER = "initializer"; //$NON-NLS-1$
	private static final String DEPENDS_ON = "dependsOn"; //$NON-NLS-1$

	/**
	 * Constructor
	 */
	public GameInitializationUtilImpl() {
		IConfigurationElement[] config = Platform.getExtensionRegistry()
				.getConfigurationElementsFor(INITIALIZER_ID);
		try {
			for (IConfigurationElement e : config) {
				GameInitializer bean = (GameInitializer) e
						.createExecutableExtension(INITIALIZER);
				List<Class<? extends Object>> dependencies = new LinkedList<Class<? extends Object>>();
				for (IConfigurationElement child : e.getChildren(DEPENDENCY)) {
					dependencies.add(child
							.createExecutableExtension(DEPENDS_ON).getClass());
				}
				initializerDependencies.put(bean, dependencies);
				initializers.add(bean);
				ReInjector.getInstance().reInject(bean);
			}
		} catch (CoreException ex) {
			System.err.println("Handle this error with log or so: " //$NON-NLS-1$
					+ ex.getMessage());
		}
		initializers = orderByDependency(initializers);
	}

	private List<GameInitializer> orderByDependency(
			List<GameInitializer> original) {
		List<GameInitializer> result = new LinkedList<GameInitializer>();
		int i = 0;
		while (original.size() > 0) {
			i = (i + 1) % original.size();
			GameInitializer gameInitializer = original.get(i);
			List dependencies = initializerDependencies.get(gameInitializer);
			if (dependencies == null || dependencies.isEmpty()
					|| containsAllClasses(result, dependencies)) {
				original.remove(gameInitializer);
				result.add(gameInitializer);
			}
		}
		return result;
	}

	private static boolean containsAllClasses(List<GameInitializer> list,
			List dependencies) {
		for (Object dep : dependencies) {
			boolean ok = false;
			for (GameInitializer gameInitializer : list) {
				if (gameInitializer.getClass().equals(dep)) {
					ok = true;
					break;
				}
			}
			if (!ok) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @return all configured initializers
	 */
	@Override
	public List<GameInitializer> getInitializers() {
		return this.initializers;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T get(Class<T> clazz) {
		for (GameInitializer initializer : initializers) {
			if (initializer.getClass().equals(clazz)) {
				return (T) initializer;
			}
		}
		return null;
	}

}
